﻿using Core.Authorization;
using Core.Exceptions;
using Core.Interfaces.Users;
using Core.Pipeline.Attributes;
using MediatR;
using Microsoft.AspNetCore.Http;

namespace Core.Identity.Common.Behaviours;

/// <summary>
/// 检查授权行为
/// </summary>
/// <typeparam name="TRequest"></typeparam>
/// <typeparam name="TResponse"></typeparam>
[PipelineOrder(0)] // 0 为最高优先级（最先注册）
public class AuthorizationBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse>
{
    private readonly ICurrentUserService _currentUser;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public AuthorizationBehaviour(
        ICurrentUserService currentUser,
        IHttpContextAccessor httpContextAccessor)
    {
        _currentUser = currentUser;
        _httpContextAccessor = httpContextAccessor;
    }

    /// <summary>
    /// 检测授权逻辑
    /// </summary>
    /// <param name="request">请求参数</param>
    /// <param name="next">进入下一管道</param>
    /// <param name="cancellationToken">取消标记</param>
    /// <returns>进入下一管道</returns>
    public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
    {
        var requiredPermissions = new List<string>();
        var httpContext = _httpContextAccessor?.HttpContext;
        if (httpContext != null)
        {
            var endpoint = httpContext.GetEndpoint();
            if (endpoint != null)
            {
                var epAttrs = endpoint.Metadata.GetOrderedMetadata<PermissionAttribute>();
                if (epAttrs != null)
                {
                    requiredPermissions = epAttrs
                        .Select(a => a.Code)
                        .Where(c => !string.IsNullOrWhiteSpace(c))
                        .ToList();
                }
            }
        }

        if (!requiredPermissions.Any())
        {
            return await next().ConfigureAwait(false);
        }

        foreach (var required in requiredPermissions)
        {
            if (!_currentUser.IsInPermission(required))
            {
                throw new ForbiddenException($"缺少权限：{required}");
            }
        }

        return await next().ConfigureAwait(false);
    }
}
